use std::sync::mpsc::SyncSender;

use glam::DVec3;

use crate::*;

pub fn demo5(tx: SyncSender<(usize, DVec3)>) -> (Renderer, Box<dyn Hitable>) {
    let ground = LambertMaterial::new(dvec3(0.48, 0.83, 0.53));

    let mut scene = Hitables::default();

    // ground boxes
    {
        let mut box1 = Hitables::default();
        let box_pre_side = 20;
        for i in 0..box_pre_side {
            for j in 0..box_pre_side {
                let w = 100.0;
                let x0 = -1000.0 + i as f64 * w;
                let z0 = -1000.0 + j as f64 * w;
                let y0 = 0.0;
                let x1 = x0 + w;
                let y1 = random_range(1.0, 101.0);
                let z1 = z0 + w;

                box1.add_boxed(make_box(dvec3(x0, y0, z0), dvec3(x1, y1, z1), ground.clone()));
            }
        }

        scene.add(BVHNode::from(box1));
    }
    
    // light
    let light = MatDiffuseLight::new(dvec3(7.0, 7.0, 7.0));
    scene.add(Quad::new(
        dvec3(123.0, 554.0, 147.0),
        dvec3(300.0, 0.0, 1.0),
        dvec3(0.0, 0.0, 265.0),
        light,
    ));

    // motion sphere, but no motion
    let sphere_material = LambertMaterial::new(dvec3(0.7, 0.3, 0.1));
    scene.add(Sphere::new(dvec3(400.0, 400.0, 200.0), 50.0, sphere_material));

    scene.add(Sphere::new(dvec3(260.0, 150.0, 45.0), 50.0, DielectricMaterial::new(1.5)));
    scene.add(Sphere::new(dvec3(0.0, 150.0, 145.0), 50.0, MetalMaterial::new(dvec3(0.8, 0.8, 0.9), 1.0)));

    let boundary = Sphere::new(
        dvec3(360.0, 150.0, 145.0),
        70.0,
        DielectricMaterial::new(1.5),
    );
    scene.add(boundary.clone());
    scene.add(ConstantMedium::new(
        Box::new(boundary),
        0.2,
        dvec3(0.2, 0.4, 0.9),
    ));

    let boundary = Sphere::new(
        dvec3(0.0, 0.0, 0.0),
        5000.0,
        DielectricMaterial::new(1.5),
    );
    scene.add(ConstantMedium::new(
        Box::new(boundary),
        0.001,
        DVec3::ONE,
    ));

    let mut box2 = Hitables::default();
    let white = LambertMaterial::new(dvec3(0.73, 0.73, 0.73));
    let ns = 1000;
    for _ in 0..ns {
        box2.add(Sphere::new(
            random_vec3_range(0.0, 165.0),
            10.0,
            white.clone(),
        ));
    }
    scene.add(Translate::new(
        dvec3(-100.0, 270.0, 395.0),
        RotateY::new(
            15.0,
            Box::new(BVHNode::from(box2)),
    )));

    let renderer = RendererBuilder::new(tx)
        .camera(
            dvec3(478.0, 278.0, -600.0),
            dvec3(278.0, 278.0, 0.0),
            dvec3(0.0, 1.0, 0.0),
            40.0,
        )
        .max_depth(4)
        .sample_count(250)
        .background(dvec3(0.0, 0.0, 0.0))
        .build();

    (renderer, Box::new(BVHNode::from(scene)))
}